<template>
  <div class="app-container">
    <!-- 搜索区域 -->
    <div class="el-advanced-search-container" v-if="showSearch">
      <el-form :model="queryParams" ref="queryForm" size="small" label-width="80px">
        <el-row :gutter="20">
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="实践项目" prop="practiceProject">
              <el-input
                v-model="queryParams.practiceProject"
                placeholder="请输入实践项目"
                clearable
                @keyup.enter.native="handleQuery"
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="实践状态" prop="practiceStatus">
              <el-select
                v-model="queryParams.practiceStatus"
                placeholder="请选择实践状态"
                clearable
              >
                <el-option label="未实践" value="0" />
                <el-option label="已实践" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="预约情况" prop="reservationStatus">
              <el-select
                v-model="queryParams.reservationStatus"
                placeholder="请选择预约情况"
                clearable
              >
                <el-option label="已报满" value="0" />
                <el-option label="未报满" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="实践时间" prop="practiceTime">
              <el-date-picker
                v-model="dateRange"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                value-format="yyyy-MM-dd"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6" style="text-align: right;">
            <el-form-item>
              <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
              <el-button type="default" icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </div>

    <!-- 操作按钮栏 -->
    <el-row :gutter="10" class="mb8">
      <el-col :span="24">
        <el-button-group>
          <el-button type="primary" plain @click="handleExport" style="margin-left: 4px;border: none;">导出</el-button>
          <el-button type="primary" plain @click="handleAdd" style="margin-left: 4px;border: none;">新建实践</el-button>
          <el-button type="primary" plain :disabled="single" @click="handleEdit" style="margin-left: 4px;border: none;">编辑实践</el-button>
          <el-button type="danger" plain :disabled="multiple" @click="handleDelete" style="margin-left: 4px;border: none;">删除</el-button>
          <el-button type="primary" plain :disabled="single" @click="handleReservationStatus" style="margin-left: 4px;border: none;">预约情况</el-button>
          <el-button type="primary" plain @click="handleNotifyStudents" style="margin-left: 4px;border: none;">通知学员</el-button>
          <el-button type="primary" plain :disabled="single" @click="handleSignInQr" style="margin-left: 4px;border: none;">签到二维码</el-button>
          <el-button type="primary" plain :disabled="single" @click="handleSignInStatus" style="margin-left: 4px;border: none;">签到情况</el-button>
        </el-button-group>

        <el-button-group style="margin-left: 20px;">
          <el-button type="primary" plain @click="toggleSearch">{{ showSearch ? '隐藏搜索' : '显示搜索' }}</el-button>
          <el-button type="primary" plain @click="handleRefresh">刷新</el-button>
        </el-button-group>
      </el-col>
    </el-row>

    <!-- 数据表格 -->
    <el-table
      v-loading="loading"
      :data="practiceList"
      @selection-change="handleSelectionChange"
      border
      stripe
      style="width: 100%;"
      :row-key="row => row.practiceAppointmentId"
    >
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="实践项目名称" align="center" prop="practiceAppointmentName" width="180" />
      <el-table-column label="实践项目" align="center" prop="practicalProjectName" width="180" />
      <el-table-column label="开始时间" align="center" prop="practiceStartTime" width="160">
        <template slot-scope="scope">{{ scope.row.practiceStartTime | formatDateTime }}</template>
      </el-table-column>
      <el-table-column label="结束时间" align="center" prop="practiceEndTime" width="160">
        <template slot-scope="scope">{{ scope.row.practiceEndTime | formatDateTime }}</template>
      </el-table-column>
      <el-table-column label="地址" align="center" prop="practiceAddress" width="180" />
      <el-table-column label="教师" align="center" prop="practicalTeacherName" width="100" />
      <el-table-column label="实践状态" align="center" prop="practicalType" width="100">
        <template slot-scope="scope">
          <el-tag :type="scope.row.practicalType === '0' ? 'info' : 'success'">
            {{ scope.row.practicalTypeName || (scope.row.practicalType === '0' ? '未实践' : '已实践') }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="预约情况" align="center" prop="appointmentType" width="100">
        <template slot-scope="scope">
          <el-tag :type="scope.row.appointmentType === '0' ? 'danger' : 'success'">
            {{ scope.row.appointmentTypeName || (scope.row.appointmentType === '0' ? '已报满' : '未报满') }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="限制人数" align="center" prop="restrictionNum" width="100" />
      <el-table-column label="报名人数" align="center" prop="registrationNum" width="100" />
      <el-table-column label="创建时间" align="center" prop="createTime" width="160">
        <template slot-scope="scope">{{ scope.row.createTime | formatDateTime }}</template>
      </el-table-column>
      <el-table-column label="操作" align="center" width="200" fixed="right">
        <template slot-scope="scope">
          <!-- <el-button
            size="mini"
            type="text"
            icon="el-icon-view"
            @click="handleView(scope.row)"
            v-hasPermi="['practice:view']"
          >查看</el-button> -->
          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="handleEdit(scope.row)"
            v-hasPermi="['practice:edit']"
          >编辑</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-user"
            @click="handleViewReservations(scope.row)"
            v-hasPermi="['practice:reservationView']"
          >预约情况</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['practice:delete']"
          >删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 分页 -->
    <pagination
      v-show="total > 0"
      :total="total"
      :page.sync="queryParams.pageNum"
      :limit.sync="queryParams.pageSize"
      @pagination="getList"
      style="margin-top: 15px"
    />

    <!-- 新建/编辑实践弹窗 -->
    <el-dialog
      :title="title"
      :visible.sync="open"
      width="800px"
      append-to-body
      :close-on-click-modal="false"
      @close="resetForm"
      destroy-on-close
    >
      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
        <el-row :gutter="24">
          <el-col :span="12">
            <el-form-item label="实践项目名称" prop="practiceAppointmentName">
              <el-input v-model="form.practiceAppointmentName" placeholder="请输入实践项目名称"></el-input>
            </el-form-item>
            <el-form-item label="实践项目" prop="practicalProjectId">
              <el-select
                class="main-select-tree"
                ref="projectSelectTree"
                v-model="form.practicalProjectId"
                style="width: 100%;"
                name="projectSelect"
                placeholder="请选择实践项目"
                clearable
                @clear="handleProjectClear"
              >
                <el-option
                  v-for="item in optionData(projectOptions)"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                  style="display: none;"
                />
                <el-tree
                  class="main-select-el-tree"
                  ref="projectSelectelTree"
                  :data="projectOptions"
                  :props="treeProps"
                  node-key="id"
                  :expand-on-click-node="true"
                  highlight-current
                  @node-click="handleProjectNodeClick"
                  default-expand-all
                />
              </el-select>
            </el-form-item>

            <!-- 实践结束时间 -->
            <el-form-item label="实践结束时间" prop="practiceEndTime">
              <el-date-picker
                v-model="form.practiceEndTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                placeholder="请选择结束时间"
                style="width: 100%;"
                :disabled-date="disabledPastDate"
                :disabled-hours="() => getDisabledHours('end')"
                :disabled-minutes="(h) => getDisabledMinutes('end', h)"
              />
            </el-form-item>

            <!-- 实践教师 -->
            <el-form-item label="实践教师" class="form-item" prop="practiceTeacher">
              <el-select
                ref="practiceTeacherSelect"
                v-model="form.practiceTeacher"
                placeholder="请选择实践教师"
                class="custom-input"
                @change="handlePracticeTeacherChange"
                @clear="handlePracticeTeacherClear"
                clearable
              >
                <el-option
                  v-if="memberOptions.length === 0"
                  value=""
                  disabled
                >
                  人员数据加载中...
                </el-option>
                <el-option
                  v-else
                  v-for="user in memberOptions"
                  :key="user.userId"
                  :label="user.nickName || user.userName"
                  :value="user.userId.toString()"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>

          <el-col :span="12">
            <!-- 实践地址 -->
            <el-form-item label="实践地址" prop="practiceAddress">
              <el-input v-model="form.practiceAddress" placeholder="请输入实践地址" />
            </el-form-item>

            <!-- 实践开始时间 -->
            <el-form-item label="实践开始时间" prop="practiceStartTime">
              <el-date-picker
                v-model="form.practiceStartTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                placeholder="请选择开始时间"
                style="width: 100%;"
                :disabled-date="disabledPastDate"
              />
            </el-form-item>

            <!-- 限制人数 -->
            <el-form-item label="限制人数" prop="restrictionNum">
              <el-input
                v-model.number="form.restrictionNum"
                placeholder="请输入限制人数"
                type="number"
                min="1"
              />
            </el-form-item>
          </el-col>
        </el-row>

        <!-- 可预约班级 -->
        <el-form-item label="可预约班级" prop="reservationScope">
          <div class="reservation-item" style="margin-top: 12px;">
            <div class="class-tag-group">
              <el-button
                type="primary" plain
                @click="openClassSelect('specifiedUnpracticed')"
              >选择教学班</el-button>
              <span v-if="form.specifiedUnpracticedClasses.length === 0" class="empty-tip">未选择班级</span>
              <el-tag
                v-else
                v-for="(cls, idx) in form.specifiedUnpracticedClasses"
                :key="cls.classId"
                closable
                @close="removeClass(idx, 'specifiedUnpracticed')"
              >{{ cls.className }}</el-tag>
            </div>
          </div>
        </el-form-item>

        <!-- 培训内容 -->
        <el-form-item label="培训内容" prop="practicalTrainingContent">
          <el-input v-model="form.practicalTrainingContent" type="textarea" rows="4" placeholder="请输入培训内容" />
        </el-form-item>

        <!-- 备注 -->
        <el-form-item label="备注" prop="remarks">
          <el-input v-model="form.remarks" type="textarea" rows="4" placeholder="请输入备注" />
        </el-form-item>
      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button @click="cancel">取消</el-button>
        <el-button type="primary" @click="submitForm">提交</el-button>
      </div>
    </el-dialog>

    <!-- 指定班级弹窗 -->
    <el-dialog :title="classTitle" :visible.sync="classSelectOpen" width="1200px" append-to-body :close-on-click-modal="false">
      <div class="flex-layout">
        <!-- 左侧：实践项目树 -->
        <div class="tree-area">
          <el-input
            placeholder="搜索实践项目"
            v-model="treeSearch"
            clearable
            style="margin-bottom: 10px;"
          />
          <el-tree
            :data="projectOptions"
            :props="{ label: 'label', children: 'children', id: 'id' }"
            :filter-node-method="filterTree"
            ref="trainingTree"
            node-key="id"
            default-expand-all
            @node-click="handleTreeSelect"
            highlight-current
          />
        </div>

        <!-- 右侧：搜索表单 + 班级表格 + 分页 -->
        <div class="content-area">
          <el-form :model="classQuery" ref="classQueryForm" size="small" label-width="100px">
            <el-row :gutter="20">
              <el-col :xs="24" :sm="12" :md="8">
                <el-form-item label="培训班编号" prop="trainingClassCode">
                  <el-input
                    v-model="classQuery.trainingClassCode"
                    placeholder="请输入培训班编号"
                    clearable
                    @keyup.enter.native="trainingClassList"
                  />
                </el-form-item>
              </el-col>
              <el-col :xs="24" :sm="12" :md="8">
                <el-form-item label="培训班名称" prop="trainingClassName">
                  <el-input
                    v-model="classQuery.trainingClassName"
                    placeholder="请输入培训班名称"
                    clearable
                    @keyup.enter.native="trainingClassList"
                  />
                </el-form-item>
              </el-col>
              <el-col :xs="24" :sm="12" :md="8">
                <el-form-item label="班主任" prop="headTeacherName">
                  <el-input
                    v-model="classQuery.headTeacherName"
                    placeholder="请输入班主任"
                    clearable
                    @keyup.enter.native="trainingClassList"
                  />
                </el-form-item>
              </el-col>

            </el-row>
            <el-row>
              <el-col :xs="24" :sm="12" :md="6">
                <el-form-item label="开班时间" prop="startDate">
                  <el-date-picker
                    v-model="classQuery.startDate"
                    type="daterange"
                    range-separator="至"
                    start-placeholder="开始日期"
                    end-placeholder="结束日期"
                    value-format="yyyy-MM-dd"
                    clearable
                  />
                </el-form-item>
              </el-col>
              <el-col :xs="24" :sm="12" :md="12" style="text-align: right;">
                <el-form-item>
                  <el-button type="primary" icon="el-icon-search" size="mini" @click="trainingClassList">搜索</el-button>
                  <el-button type="default" icon="el-icon-refresh" size="mini" @click="resetClassQuery">重置</el-button>
                </el-form-item>
              </el-col>
            </el-row>
          </el-form>

          <el-table
            ref="classTable"
            v-loading="classLoading"
            :data="classList"
            @selection-change="handleClassSelection"
            border
            stripe
            style="width: 100%;"
            :row-key="row => row.trainingClassId"
          >
            <el-table-column type="selection" width="55" align="center" />
            <el-table-column label="培训班编号" align="center" prop="trainingClassCode" width="120" />
            <el-table-column label="培训班名称" align="center" prop="trainingClassName" width="180" />
            <el-table-column label="年份" align="center" prop="trainingYear" width="80" />
            <el-table-column label="期次" align="center" prop="trainingSession" width="80" />
            <el-table-column label="培训类型" align="center" prop="trainingType" width="120">
              <template slot-scope="scope">
                <el-tag
                  :type="
                    scope.row.trainingType === '1' ? 'info' :
                    scope.row.trainingType === '2' ? 'primary' :
                    scope.row.trainingType === '3' ? 'success' :
                    scope.row.trainingType === '0' ? 'warning' : ''
                  "
                >
                  {{ getTrainingTypeLabel(scope.row.trainingType) }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column label="培训项目" align="center" prop="trainingProjectNames" width="120" />
            <el-table-column label="培训人数" align="center" prop="totalQuota" width="100" />
            <el-table-column label="培训开始日期" align="center" prop="startDate" width="160">
              <template slot-scope="scope">{{ scope.row.startDate | formatDate }}</template>
            </el-table-column>
            <el-table-column label="班主任" align="center" width="140">
              <template slot-scope="scope">
                {{
                  scope.row.headTeacher1Name || scope.row.headTeacher2Name
                    ? `${scope.row.headTeacher1Name || ''}${scope.row.headTeacher2Name ? '/' + scope.row.headTeacher2Name : ''}`
                    : '无'
                }}
              </template>
            </el-table-column>
          </el-table>

          <pagination
            v-show="classTotal > 0"
            :total="classTotal"
            :page.sync="classQuery.pageNum"
            :limit.sync="classQuery.pageSize"
            @pagination="trainingClassList"
            style="margin-top: 15px"
          />
          <div slot="footer" class="dialog-footer">
            <el-button @click="closeClassSelect">取消</el-button>
            <el-button type="primary" @click="confirmClass" :disabled="selectedClasses.length === 0">确定</el-button>
          </div>
        </div>
      </div>
    </el-dialog>

    <!-- 预约人员弹窗（已适配后端数据） -->
    <el-dialog :title="studentTitle" :visible.sync="studentSelectOpen" width="1000px" append-to-body :close-on-click-modal="false">
      <el-form :model="studentQuery" ref="studentQueryForm" size="small" label-width="80px">
        <el-row :gutter="20">
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="姓名" prop="name">
              <el-input
                v-model="studentQuery.name"
                placeholder="请输入姓名"
                clearable
                @keyup.enter.native="getClassStudents"
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="证件编号" prop="idCard">
              <el-input
                v-model="studentQuery.idCard"
                placeholder="请输入证件编号"
                clearable
                @keyup.enter.native="getClassStudents"
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="培训班" prop="className">
              <el-input
                v-model="studentQuery.className"
                placeholder="请输入培训班名称"
                clearable
                @keyup.enter.native="getClassStudents"
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="考试状态" prop="examStatus">
              <el-select
                v-model="studentQuery.examStatus"
                placeholder="请选择考试状态"
                clearable
              >
                <el-option label="未排考" value="0" />
                <el-option label="已排考" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :xs="24" :sm="12" :md="12" style="text-align: right;">
            <el-form-item>
              <el-button type="primary" icon="el-icon-search" size="mini" @click="getClassStudents">搜索</el-button>
              <el-button type="default" icon="el-icon-refresh" size="mini" @click="resetStudentQuery">重置</el-button>
              <el-button
                type="primary"
                plain
                size="mini"
                @click="confirmStudent"
                :disabled="selectedStudents.length === 0"
              >确认选择</el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <el-table
        v-loading="studentLoading"
        :data="studentList"
        @selection-change="handleStudentSelection"
        border
        stripe
        style="width: 100%;"
        :row-key="row => row.idCard"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="姓名" align="center" prop="name" width="100" />
        <el-table-column label="证件编号" align="center" prop="idCard" width="180" />
        <el-table-column label="电话" align="center" prop="phone" width="120" />
        <!-- <el-table-column label="单位名称" align="center" prop="company" width="120" /> -->
        <el-table-column label="培训项目" align="center" prop="trainingProject" width="120" />
        <el-table-column label="培训班编号" align="center" prop="trainingClassCode" width="120" />
        <el-table-column label="培训班" align="center" prop="className" width="120" />
        <el-table-column label="班主任" align="center" prop="teacher" width="100" />
        <el-table-column label="实践状态" align="center" prop="practiceStatus" width="100">
          <template slot-scope="scope">
            <el-tag :type="scope.row.practiceStatus === '0' ? 'info' : 'success'">
              {{ scope.row.practiceStatusName || (scope.row.practiceStatus === '0' ? '未实践' : '已实践') }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="考试状态" align="center" prop="examStatus" width="100">
          <template slot-scope="scope">
            <el-tag :type="scope.row.examStatus === '0' ? 'info' : 'success'">
              {{ scope.row.examStatusName || (scope.row.examStatus === '0' ? '未排考' : '已排考') }}
            </el-tag>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="studentTotal > 0"
        :total="studentTotal"
        :page.sync="studentQuery.pageNum"
        :limit.sync="studentQuery.pageSize"
        @pagination="getClassStudents"
        style="margin-top: 15px"
      />
      <div slot="footer" class="dialog-footer">
        <el-button @click="closeStudentSelect">关闭</el-button>
      </div>
    </el-dialog>

    <!-- 预约情况弹窗 -->
    <el-dialog :title="reservationTitle" :visible.sync="reservationOpen" width="1200px" append-to-body :close-on-click-modal="false">
      <el-row :gutter="20" style="margin-bottom: 15px;">
        <el-col :span="24">
          <div class="reservation-info">
            <p><strong>实践项目名称：</strong>{{ currentPractice.practiceAppointmentName || '' }}</p>
            <p><strong>实践项目：</strong>{{ currentPractice.practicalProjectName || '' }}</p>
            <p><strong>实践时间：</strong>{{ currentPractice.practiceStartTime ? `${currentPractice.practiceStartTime } 至 ${currentPractice.practiceEndTime }` : '' }}</p>
            <p><strong>实践地址：</strong>{{ currentPractice.practiceAddress || '' }}</p>
            <p><strong>实践教师：</strong>{{ currentPractice.practicalTeacherName || '' }}</p>
            <p><strong>限制人数：</strong>{{ currentPractice.restrictionNum || 0 }}人</p>
            <p><strong>已预约人数：</strong>{{ reservationList.length }}人</p>
            <p><strong>剩余名额：</strong>{{ (currentPractice.restrictionNum || 0) - reservationList.length }}人</p>
          </div>
        </el-col>
      </el-row>

      <el-form :model="reservationQuery" ref="reservationQueryForm" size="small" label-width="80px">
        <el-row :gutter="20">
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="姓名" prop="name">
              <el-input
                v-model="reservationQuery.name"
                placeholder="请输入姓名"
                clearable
                @keyup.enter.native="getReservationList"
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="证件编号" prop="idCard">
              <el-input
                v-model="reservationQuery.idCard"
                placeholder="请输入证件编号"
                clearable
                @keyup.enter.native="getReservationList"
              />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="预约来源" prop="source">
              <el-select
                v-model="reservationQuery.source"
                placeholder="请选择预约来源"
                clearable
              >
                <el-option label="自主预约" value="0" />
                <el-option label="管理员添加" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="实践项目" prop="projectId">
              <el-select
                class="main-select-tree"
                ref="reservationProjectSelectTree"
                v-model="reservationQuery.projectId"
                style="width: 100%;"
                placeholder="请选择实践项目"
                clearable
                @clear="handleReservationProjectClear"
              >
                <el-option
                  v-for="item in optionData(projectOptions)"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                  style="display: none;"
                />
                <el-tree
                  class="main-select-el-tree"
                  ref="reservationProjectSelectelTree"
                  :data="projectOptions"
                  :props="treeProps"
                  node-key="id"
                  :expand-on-click-node="true"
                  highlight-current
                  @node-click="handleReservationProjectNodeClick"
                  default-expand-all
                />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :xs="24" :sm="12" :md="6">
            <el-form-item label="签到状态" prop="signStatus">
              <el-select
                v-model="reservationQuery.signStatus"
                placeholder="请选择签到状态"
                clearable
              >
                <el-option label="未签到" value="0" />
                <el-option label="已签到" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :xs="24" :sm="12" :md="6" style="text-align: right;margin-left:200px">
            <el-form-item>
              <el-button type="primary" icon="el-icon-search" size="mini" @click="getReservationList">搜索</el-button>
              <el-button type="default" icon="el-icon-refresh" size="mini" @click="resetReservationQuery">重置</el-button>
              <el-button
                type="primary"
                plain
                size="mini"
                @click="openAddReservation"
                :disabled="(currentPractice.restrictionNum || 0) <= reservationList.length"
              >添加预约</el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>

      <el-table
        v-loading="reservationLoading"
        :data="reservationList"
        @selection-change="handleReservationSelection"
        border
        stripe
        style="width: 100%;"
        :row-key="row => row.reservationId"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="序号" align="center" type="index" width="60" />
        <el-table-column label="姓名" align="center" prop="name" width="100" />
        <el-table-column label="证件编号" align="center" prop="idCard" width="180" />
        <el-table-column label="电话" align="center" prop="phone" width="120" />
        <el-table-column label="单位名称" align="center" prop="company" width="120" />
        <el-table-column label="培训班" align="center" prop="className" width="120" />
        <el-table-column label="预约来源" align="center" prop="source" width="100">
          <template slot-scope="scope">
            <el-tag :type="scope.row.source === '0' ? 'info' : 'primary'">
              {{ scope.row.source === '0' ? '自主预约' : '管理员添加' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="预约时间" align="center" prop="reservationTime" width="160">
          <template slot-scope="scope">{{ scope.row.reservationTime | formatDateTime }}</template>
        </el-table-column>
        <el-table-column label="签到状态" align="center" prop="signStatus" width="100">
          <template slot-scope="scope">
            <el-tag :type="scope.row.signStatus === '0' ? 'warning' : 'success'">
              {{ scope.row.signStatus === '0' ? '未签到' : '已签到' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="签到时间" align="center" width="160">
          <template slot-scope="scope">{{ scope.row.signTime ? (scope.row.signTime | formatDateTime) : '-' }}</template>
        </el-table-column>
        <el-table-column label="操作" align="center" width="160" fixed="right">
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="text"
              icon="el-icon-check"
              @click="handleSignIn(scope.row)"
              v-if="scope.row.signStatus === '0'"
              :disabled="isPracticeExpired"
            >签到</el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-delete"
              @click="handleCancelReservation(scope.row)"
            >取消预约</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="reservationTotal > 0"
        :total="reservationTotal"
        :page.sync="reservationQuery.pageNum"
        :limit.sync="reservationQuery.pageSize"
        @pagination="getReservationList"
        style="margin-top: 15px"
      />
      <div slot="footer" class="dialog-footer">
        <el-button @click="closeReservation">关闭</el-button>
        <el-button
          type="primary"
          @click="handleBatchSignIn"
          v-if="canSignIn"
          :disabled="isPracticeExpired || selectedReservations.length === 0"
        >批量签到</el-button>
        <el-button
          type="danger"
          plain
          @click="handleBatchCancelReservation"
          v-if="selectedReservations.length > 0"
        >批量取消预约</el-button>
      </div>
    </el-dialog>

    <!-- 签到二维码弹窗 -->
    <el-dialog :title="qrCodeTitle" :visible.sync="qrCodeOpen" width="400px" append-to-body :close-on-click-modal="false">
      <div class="qr-code-container">
        <div class="qr-code">
          <div class="mock-qr">
            <div class="mock-qr-corner"></div>
            <div class="mock-qr-corner" style="top: 10px; right: 10px; border-left: none; border-bottom: none;"></div>
            <div class="mock-qr-corner" style="bottom: 10px; left: 10px; border-right: none; border-top: none;"></div>
            <div class="mock-qr-content">
              <p>签到二维码</p>
              <p class="project-name">{{ currentPractice.practiceAppointmentName || '' }}</p>
            </div>
          </div>
          <div class="qr-countdown" v-if="qrExpireCountdown > 0">
            剩余有效时间：{{ qrExpireCountdown }}秒
          </div>
          <div class="qr-countdown expired" v-else>
            二维码已过期，请点击刷新
          </div>
        </div>
        <div class="qr-info">
          <p>实践项目：{{ currentPractice.practicalProjectName || '' }}</p>
          <p>实践时间：{{ currentPractice.practiceStartTime | formatDateTime }}</p>
          <p>有效期：15分钟</p>
        </div>
        <el-button
          type="primary"
          style="width: 100%; margin-top: 20px;"
          @click="refreshQrCode"
          :loading="isRefreshingQr"
        >刷新二维码</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import Pagination from "@/components/Pagination";
import {
  listPracticeAppointment,
  getPracticeAppointment,
  addPracticeAppointment,
  updatePracticeAppointment,
  delPracticeAppointment,
  selectListByQuery,
  insertPracticeAppointment,
  editPracticeAppointment,
  removePracticeAppointment
} from '@/api/training/practiceAppointment';
import { trainingClassList as fetchClassList } from '@/api/training/TrainingClass';
import { selectStudentsWhenAdd } from "@/api/training/practiceClass.js";
import { projectTreeSelect } from "@/api/training/projects";
import { queryNonMemberUsers } from "@/api/system/user"

export default {
  name: "PracticeList",
  dicts: ["training_type", "class_status","start_up_type","sign_up_category"],
  components: { Pagination },
  filters: {
    formatDateTime(value) {
      if (!value) return '';
      const date = new Date(value);
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, '0');
      const day = String(date.getDate()).padStart(2, '0');
      const hour = String(date.getHours()).padStart(2, '0');
      const minute = String(date.getMinutes()).padStart(2, '0');
      const second = String(date.getSeconds()).padStart(2, '0');
      return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
    },
    formatDate(value) {
      if (!value) return '';
      const date = new Date(value);
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, '0');
      const day = String(date.getDate()).padStart(2, '0');
      return `${year}-${month}-${day}`;
    }
  },
  data() {
    // 定义初始表单结构
    const initialForm = {
      practiceAppointmentId: null,
      practiceAppointmentName: '',
      practicalProjectId: null,
      practiceStartTime: null,
      practiceEndTime: null,
      practiceAddress: '',
      practiceTeacher: '',
      practiceTeacherName: '',
      restrictionNum: null,
      practicalTrainingContent: '',
      reservationScope: ['specifiedUnpracticed'],
      specifiedUnpracticedClasses: [],
      remarks: '',
      practicalProjectName: '',
      practicalTeacherId: null,
      trainingClassList: []
    };

    return {
      loading: false,
      ids: [],
      single: true,
      multiple: true,
      showSearch: true,
      total: 0,
      practiceList: [],
      dateRange: [],

      queryParams: {
        pageNum: 1,
        pageSize: 10,
        practiceProject: null,
        practiceStatus: null,
        reservationStatus: null,
        practiceTime: []
      },

      projectOptions: [],
      memberOptions: [],
      treeProps: {
        children: 'children',
        label: 'label'
      },

      // 树搜索相关（指定班级弹窗左侧树）
      treeSearch: '',

      open: false,
      title: "",
      form: JSON.parse(JSON.stringify(initialForm)),
      initialForm: initialForm,
      rules: {
        practiceAppointmentName: [
          { required: true, message: "请输入实践项目名称", trigger: "blur" }
        ],
        practicalProjectId: [
          { required: true, message: "请选择实践项目", trigger: "change" },
          {
            validator: (rule, value, callback) => {
              if (value === null || value === undefined || value === "") {
                callback(new Error("请选择有效的实践项目"));
              } else {
                callback();
              }
            },
            trigger: "change"
          }
        ],
        practiceStartTime: [
          { required: true, message: "请选择实践开始时间", trigger: "change" },
          { validator: this.validateStartTime, trigger: "change" }
        ],
        practiceEndTime: [
          { required: true, message: "请选择实践结束时间", trigger: "change" },
          { validator: this.validateEndTime, trigger: "change" }
        ],
        practiceAddress: [{ required: true, message: "请输入实践地址", trigger: "blur" }],
        practiceTeacher: [{ required: true, message: "请选择实践教师", trigger: "change" }],
        restrictionNum: [
          { required: true, message: "请输入限制人数", trigger: "blur" },
          { type: "number", min: 1, message: "限制人数必须为正整数", trigger: "blur" }
        ],
        specifiedUnpracticedClasses: [
          { required: true, message: "请选择可预约班级", trigger: "change" },
          { type: "array", min: 1, message: "至少选择一个班级", trigger: "change" }
        ]
      },

      classSelectOpen: false,
      classSelectType: '',
      classTitle: "选择班级",
      classQuery: {
        pageNum: 1,
        pageSize: 10,
        trainingClassCode: null,
        trainingClassName: null,
        headTeacherName: null,
        startDate: [],
        projectId: null, // 用于接收左侧树选择的项目ID
      },
      classLoading: false,
      classList: [],
      classTotal: 0,
      selectedClasses: [],
      selectedClassIds: [],

      studentSelectOpen: false,
      studentTitle: "",
      studentQuery: {
        pageNum: 1,
        pageSize: 10,
        name: null,
        idCard: null,
        className: null,
        examStatus: null,
        practiceProjectId: null,
        classIds: [],
        practiceAppointmentId:null,
        practiceStatus:null,
      },
      studentLoading: false,
      studentList: [],
      studentTotal: 0,
      selectedStudents: [],
      currentPractice: {},

      reservationOpen: false,
      reservationTitle: "预约情况",
      reservationQuery: {
        pageNum: 1,
        pageSize: 10,
        name: null,
        idCard: null,
        source: null,
        signStatus: null,
        projectId: null
      },
      reservationLoading: false,
      reservationList: [],
      reservationTotal: 0,
      selectedReservations: [],
      canSignIn: false,

      qrCodeOpen: false,
      qrCodeTitle: "签到二维码",
      qrExpireCountdown: 900,
      qrTimer: null,
      isRefreshingQr: false
    };
  },
  computed: {
    isPracticeExpired() {
      if (!this.currentPractice.practiceEndTime) return false;
      return new Date(this.currentPractice.practiceEndTime) < new Date();
    }
  },
  watch: {
    // 监听树搜索关键词，实时过滤树节点
    treeSearch(val) {
      this.$refs.trainingTree.filter(val);
    }
  },
  created() {
    this.getList();
    this.getProjectTree();
    this.getMembersList();
  },
  beforeDestroy() {
    if (this.qrTimer) clearInterval(this.qrTimer);
  },
  methods: {
    // 实践教师选择变更处理
    handlePracticeTeacherChange() {
      const teacherId = this.form.practiceTeacher;
      this.form.practiceTeacherName = teacherId ? '' : '';
      if (!teacherId) return;

      const matchedTeacher = this.memberOptions.find(
        user => user.userId === teacherId
      );
      if (matchedTeacher) {
        this.form.practiceTeacherName = matchedTeacher.nickName || matchedTeacher.userName;
      }
    },

    // 实践教师清空处理
    handlePracticeTeacherClear() {
      this.form.practiceTeacher = '';
      this.form.practiceTeacherName = '';
    },

    // 加载人员列表
    async getMembersList() {
      try {
        const userRes = await queryNonMemberUsers();
        this.memberOptions = userRes.rows || [];
      } catch (error) {
        console.error("人员数据加载失败：", error);
        this.$message.error("人员信息加载失败，请稍后重试");
        this.memberOptions = [];
      }
    },

    // 加载项目树形数据（供左侧树使用）
    getProjectTree() {
      projectTreeSelect({}).then(response => {
        this.projectOptions = response.data || [];
      }).catch(err => {
        console.error('获取项目树形数据失败：', err);
        this.$message.error('加载实践项目失败，请刷新重试');
      });
    },

    optionData(array, result = []) {
      array.forEach((item) => {
        result.push({ label: item.label, value: item.id });
        if (item.children && item.children.length !== 0) {
          this.optionData(item.children, result);
        }
      });
      return JSON.parse(JSON.stringify(result));
    },

    handleProjectNodeClick(node) {
      this.form.practicalProjectId = node.id;
      this.$refs.projectSelectTree.blur();
    },

    handleProjectClear() {
      this.form.practicalProjectId = null;
      if (this.$refs.projectSelectelTree) {
        this.$refs.projectSelectelTree.setCurrentKey(null);
      }
    },

    // 预约情况弹窗的项目选择处理
    handleReservationProjectNodeClick(node) {
      this.reservationQuery.projectId = node.id;
      this.$refs.reservationProjectSelectTree.blur();
      this.getReservationList();
    },

    handleReservationProjectClear() {
      this.reservationQuery.projectId = null;
      if (this.$refs.reservationProjectSelectelTree) {
        this.$refs.reservationProjectSelectelTree.setCurrentKey(null);
      }
      this.getReservationList();
    },

    // 获取实践列表
    getList() {
      this.loading = true;
      let  param = {
        projectName: this.queryParams.practiceProject || '',
        practicalType: this.queryParams.practiceStatus || '',
        appointmentType: this.queryParams.reservationStatus || '',
        beginTime: this.queryParams.practiceTime[0] || '',
        endTime: this.queryParams.practiceTime[1] || '',
        pageNum: this.queryParams.pageNum,
        pageSize: this.queryParams.pageSize
      };
      selectListByQuery(param).then(res => {
        if (res.code === 200) {
          this.practiceList = res.rows;
          this.total = res.total;
        } else {
          this.$message.error(res.msg || '获取实践列表失败');
        }
      }).catch(err => {
        console.error('获取实践列表异常：', err);
        this.$message.error('网络异常，请重试');
      }).finally(() => {
        this.loading = false;
      });
    },

    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },

    resetQuery() {
      if (this.$refs.queryForm) this.$refs.queryForm.resetFields();
      this.dateRange = [];
      this.queryParams.practiceTime = [];
      this.handleQuery();
    },

    toggleSearch() {
      this.showSearch = !this.showSearch;
    },

    handleRefresh() {
      this.getList();
      this.$message.success("列表已刷新");
    },

    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.practiceAppointmentId);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },

    // 新建实践
    handleAdd() {
      this.resetForm();
      this.open = true;
      this.title = "添加实践";
    },

    // 编辑实践
    handleEdit(row) {
      this.resetForm();

      const id = row ? row.practiceAppointmentId : this.ids[0];
      let  param = {
        practiceAppointmentId:id,
      };

      selectListByQuery(param).then(res => {
        if (res.code === 200 && res.rows && res.rows.length > 0) {
          const rowData = res.rows[0];

          this.form = Object.assign({}, this.form, {
            practiceAppointmentId: rowData.practiceAppointmentId,
            practiceAppointmentName: rowData.practiceAppointmentName || '',
            practicalProjectId: rowData.practicalProjectId || null,
            practiceStartTime: rowData.practiceStartTime
              ? (rowData.practiceStartTime.includes(' ')
                  ? rowData.practiceStartTime
                  : `${rowData.practiceStartTime} 08:00:00`)
              : null,
            practiceEndTime: rowData.practiceEndTime
              ? (rowData.practiceEndTime.includes(' ')
                  ? rowData.practiceEndTime
                  : `${rowData.practiceEndTime} 17:00:00`)
              : null,
            practiceAddress: rowData.practiceAddress || '',
            practiceTeacher: rowData.practicalTeacherId || '',
            restrictionNum: rowData.restrictionNum || null,
            practicalTrainingContent: rowData.practicalTrainingContent || '',
            remarks: rowData.remarks || '',
            specifiedUnpracticedClasses: []
          });

          const matchedTeacher = this.memberOptions.find(
            user => user.userId === this.form.practiceTeacher
          );
          this.form.practiceTeacherName = matchedTeacher
            ? (matchedTeacher.nickName || matchedTeacher.userName)
            : '';

          if (rowData.trainingClassList && Array.isArray(rowData.trainingClassList)) {
            this.form.specifiedUnpracticedClasses = rowData.trainingClassList.map(cls => ({
              classId: cls.trainingClassId,
              className: cls.trainingClassName || `班级ID: ${cls.trainingClassId}`
            }));
          }

          this.$nextTick(() => {
            if (this.form.practicalProjectId && this.$refs.projectSelectelTree) {
              const findNode = (tree, id) => {
                for (const node of tree) {
                  if (node.id === id) return node;
                  if (node.children) {
                    const childNode = findNode(node.children, id);
                    if (childNode) return childNode;
                  }
                }
                return null;
              };
              const targetNode = findNode(this.projectOptions, this.form.practicalProjectId);
              if (targetNode) {
                this.$refs.projectSelectelTree.setCurrentKey(targetNode.id);
              }
            }
          });

          this.open = true;
          this.title = "编辑实践";
        } else {
          this.$message.error(res.msg || '获取详情失败');
        }
      }).catch(err => {
        console.error('获取实践详情异常：', err);
        this.$message.error('网络异常，请重试');
      });
    },

    // 查看详情
    handleView(row) {
      this.handleEdit(row);
      this.$nextTick(() => {
        setTimeout(() => {
          const formItems = this.$refs.form?.$el?.querySelectorAll('.el-form-item');
          if (formItems) {
            formItems.forEach(item => {
              const inputs = item.querySelectorAll('input, select, textarea');
              inputs.forEach(input => input.disabled = true);
              const buttons = item.querySelectorAll('.el-button');
              buttons.forEach(button => button.disabled = true);
            });
          }
        }, 100);
      });
    },

    // 提交表单
    submitForm() {
      this.$refs.form.validate(valid => {
        if (valid) {
          const isEdit = !!this.form.practiceAppointmentId;
          const method = isEdit ? editPracticeAppointment : insertPracticeAppointment;

          const practicalClassIds = this.form.specifiedUnpracticedClasses.map(cls => cls.classId);

          const submitData = {
            ...this.form,
            trainingClassIds :practicalClassIds,
            practicalTeacherId: this.form.practiceTeacher
          };

          delete submitData.practiceTeacher;
          delete submitData.practiceTeacherName;
          delete submitData.specifiedUnpracticedClasses;
          delete submitData.trainingClassList;
          delete submitData.practicalProjectName;
          console.log(submitData)

           method(submitData).then(res => {
            if (res.code === 200) {
              this.$message.success(isEdit ? '修改成功' : '新增成功');
              this.open = false;
              this.getList();
            } else {
              this.$message.error(res.msg || (isEdit ? '修改失败' : '新增失败'));
            }
          }).catch(err => {
            console.error(`${isEdit ? '修改' : '新增'}实践异常：`, err);
            this.$message.error('网络异常，请重试');
          });
        }
      });
    },

    // 重置表单
    resetForm() {
      this.form = JSON.parse(JSON.stringify(this.initialForm));
      this.$nextTick(() => {
        if (this.$refs.projectSelectelTree) {
          this.$refs.projectSelectelTree.setCurrentKey(null);
        }
        if (this.$refs.practiceTeacherSelect) {
          this.$refs.practiceTeacherSelect.blur();
        }
        if (this.$refs.form) {
          this.$refs.form.clearValidate();
        }
      });
    },

    // 取消操作
    cancel() {
      this.open = false;
      this.$nextTick(() => {
        this.resetForm();
      });
    },

    // 表单验证方法
    validateStartTime(rule, value, callback) {
      if (!value) return callback();
      if (new Date(value) < new Date(new Date().setHours(0, 0, 0, 0))) {
        return callback(new Error('开始时间不能早于当前日期'));
      }
      callback();
    },

    validateEndTime(rule, value, callback) {
      if (!value) return callback();
      if (!this.form.practiceStartTime) {
        return callback(new Error('请先选择开始时间'));
      }
      if (new Date(value) <= new Date(this.form.practiceStartTime)) {
        return callback(new Error('结束时间必须晚于开始时间'));
      }
      callback();
    },

    disabledPastDate(date) {
      return date < new Date(new Date().setHours(0, 0, 0, 0));
    },

    getDisabledHours(type) {
      if (type !== 'end' || !this.form.practiceStartTime) return [];
      const startHour = new Date(this.form.practiceStartTime).getHours();
      return Array.from({ length: startHour }, (_, i) => i);
    },

    getDisabledMinutes(type, hour) {
      if (type !== 'end' || !this.form.practiceStartTime) return [];
      const startHour = new Date(this.form.practiceStartTime).getHours();
      const startMinute = new Date(this.form.practiceStartTime).getMinutes();
      if (hour !== startHour) return [];
      return Array.from({ length: startMinute }, (_, i) => i);
    },

    // 班级选择相关方法
    openClassSelect(type) {
      this.classSelectType = type;
      this.classSelectOpen = true;
      this.classTitle = "选择班级";

      this.selectedClassIds = [];
      const targetFormArray = this.form.specifiedUnpracticedClasses;
      this.selectedClassIds = targetFormArray.map(cls => cls.classId);

      this.selectedClasses = [];
      this.resetClassQuery();
    },

    closeClassSelect() {
      this.classSelectOpen = false;
      this.selectedClasses = [];
    },

    removeClass(index, type) {
      this.form.specifiedUnpracticedClasses.splice(index, 1);
    },

    // 树节点过滤方法（指定班级弹窗左侧树）
    filterTree(value, data) {
      if (!value) return true;
      return data.label.includes(value);
    },

    // 树节点点击事件（指定班级弹窗左侧树）
    handleTreeSelect(node) {
      this.classQuery.projectId = node.id; // 将选中的项目ID绑定到查询参数
      this.trainingClassList(); // 刷新班级列表
    },

    // 获取班级列表（带项目筛选）
    trainingClassList() {
      this.classLoading = true;
      const params = {
        trainingClassCode: this.classQuery.trainingClassCode || '',
        trainingClassName: this.classQuery.trainingClassName || '',
        headTeacherName: this.classQuery.headTeacherName || '',
        params:{
          beginTime: this.classQuery.startDate[0] || '',
          endTime: this.classQuery.startDate[1] || '',
        },
        projectId: this.classQuery.projectId || '', // 使用左侧树选择的项目ID筛选
        pageNum: this.classQuery.pageNum,
        pageSize: this.classQuery.pageSize
      };

      fetchClassList(params).then(res => {
        if (res.code === 200) {
          this.classList = res.rows;
          this.classTotal = res.total;
        } else {
          this.$message.error(res.msg || '获取班级列表失败');
        }
      }).catch(err => {
        console.error('获取班级列表异常：', err);
        this.$message.error('网络异常，请重试');
      }).finally(() => {
        this.classLoading = false;
        this.$nextTick(() => {
          const classTable = this.$refs.classTable;
          if (!classTable || this.selectedClassIds.length === 0) return;

          this.classList.forEach(row => {
            if (this.selectedClassIds.includes(row.trainingClassId)) {
              classTable.toggleRowSelection(row, true);
            }
          });
        });
      });
    },

    resetClassQuery() {
      if (this.$refs.classQueryForm) this.$refs.classQueryForm.resetFields();
      this.classQuery.startDate = [];
      this.classQuery.projectId = null; // 重置项目筛选
      if (this.$refs.trainingTree) {
        this.$refs.trainingTree.setCurrentKey(null); // 重置树选中状态
      }
      this.treeSearch = ''; // 清空树搜索
      this.trainingClassList();
    },

    handleClassSelection(selection) {
      this.selectedClasses = selection;
    },

    confirmClass() {
      const targetArray = this.form.specifiedUnpracticedClasses;

      const newSelectedClasses = this.selectedClasses.map(c => ({
        classId: c.trainingClassId,
        className: c.trainingClassName
      }));

      const existingIds = targetArray.map(item => item.classId);
      const filteredClasses = newSelectedClasses.filter(
        item => !existingIds.includes(item.classId)
      );

      targetArray.push(...filteredClasses);
      this.$message.success(`已选择${filteredClasses.length}个班级，共${targetArray.length}个`);
      this.closeClassSelect();
    },

    // 数据格式化：将后端返回字段映射为前端表格字段
    formatStudentData(rows) {
      return rows.map(item => ({
        // 核心字段映射
        name: item.studentName || '',
        idCard: item.idNumber || '',
        phone: item.phonenumber || '',
        classId: item.trainingClassId || '',
        trainingClassCode: item.trainingClassCode || '',
        className: item.trainingClassName || '',
        trainingProject: item.trainingProjectName || '',

        // 班主任拼接（处理两个班主任字段）
        teacher: `${item.headTeacher1Name || ''}${item.headTeacher2Name ? '/' + item.headTeacher2Name : ''}`,

        // 后端无单位名称字段，默认空
        company: '',

        // 状态字段（保留后端返回的状态名）
        practiceStatus: item.practiceStatus || '0',
        practiceStatusName: item.practiceStatusName || (item.practiceStatus === '0' ? '未实践' : '已实践'),
        examStatus: item.examStatus || '0',
        examStatusName: item.examStatusName || (item.examStatus === '0' ? '未排考' : '已排考'),

        // 保留后端原始ID（用于添加预约）
        studentId: item.studentId || ''
      }));
    },

    // 预约人员弹窗相关方法
    handleViewReservations(row) {
      const practice = row;
      this.$router.push({
        name: '实践预约预约情况',
        params: {
          practiceAppointmentId:practice.practiceAppointmentId,
          practicalProjectName: practice.practicalProjectName,
          practiceTime: practice.practiceStartTime+"---"+practice.practiceEndTime,
          practicalTeacherName: practice.practicalTeacherName,
          practiceAddress: practice.practiceAddress,
        }
      });
      // this.currentPractice = { ...row };
      // this.studentSelectOpen = true;
      // this.studentTitle = `预约人员（班级名称：${row.practiceAppointmentName || ''}）`;
      // this.selectedStudents = [];

      // this.studentQuery.practiceProjectId = row.practicalProjectId;
      // this.studentQuery.practiceAppointmentId = row.practiceAppointmentId;
      // this.studentQuery.classIds = row.specifiedUnpracticedClasses
      //   ? row.specifiedUnpracticedClasses.map(cls => cls.classId).join(',')
      //   : '';

      // this.getClassStudents();
    },

    // 获取学员列表（适配后端数据）
    getClassStudents() {
      this.studentLoading = true;
      const params = {
        studentName: this.studentQuery.name || '',  // 姓名查询参数
        idNumber: this.studentQuery.idCard || '',   // 证件编号：前端idCard -> 后端idNumber
        trainingClassName: this.studentQuery.className || '', // 培训班名称
        examStatus: this.studentQuery.examStatus || '',
        practiceAppointmentId: this.studentQuery.practiceAppointmentId || "",
        practiceStatus: this.studentQuery.practiceStatus || "",
        pageNum: this.studentQuery.pageNum,
        pageSize: this.studentQuery.pageSize
      };

      selectStudentsWhenAdd(params).then(res => {
        if (res.code === 200) {
          this.studentList = this.formatStudentData(res.rows); // 格式化后端数据
          this.studentTotal = res.total;
        } else {
          this.$message.error(res.msg || '获取学员列表失败');
        }
      }).catch(err => {
        console.error('获取学员列表异常：', err);
        this.$message.error('网络异常，请重试');
      }).finally(() => {
        this.studentLoading = false;
      });
    },

    resetStudentQuery() {
      if (this.$refs.studentQueryForm) this.$refs.studentQueryForm.resetFields();
      this.getClassStudents();
    },

    handleStudentSelection(selection) {
      this.selectedStudents = selection;
    },

    // 确认添加预约（使用格式化后的学员ID）
    confirmStudent() {
      if (this.selectedStudents.length === 0) return;

      const remainingQuota = (this.currentPractice.restrictionNum || 0) - this.reservationList.length;
      if (this.selectedStudents.length > remainingQuota) {
        this.$message.warning(`剩余名额不足，最多可添加${remainingQuota}名学员`);
        return;
      }

      const reservationData = {
        practiceId: this.currentPractice.practiceAppointmentId,
        students: this.selectedStudents.map(student => ({
          studentId: student.studentId, // 使用后端返回的studentId
          studentName: student.name,
          studentPhone: student.phone,
          className: student.className,
          source: '1'
        }))
      };

      this.$api.training.practiceAppointment.addPracticeReservation(reservationData).then(res => {
        if (res.code === 200) {
          this.$message.success(`成功添加${this.selectedStudents.length}名学员预约`);
          this.closeStudentSelect();
          this.getReservationList();
        } else {
          this.$message.error(res.msg || '添加预约失败');
        }
      }).catch(err => {
        console.error('添加预约异常：', err);
        this.$message.error('网络异常，请重试');
      });
    },

    closeStudentSelect() {
      this.studentSelectOpen = false;
      this.selectedStudents = [];
    },

    // 预约管理
    handleReservationStatus() {
      if (this.ids.length !== 1) {
        this.$message.warning("请选择单个实践项目");
        return;
      }
      const practice = this.practiceList.find(p => p.practiceAppointmentId === this.ids[0]);
      this.$router.push({
        name: '实践预约预约情况',
        params: {
          practiceAppointmentId:practice.practiceAppointmentId,
          practicalProjectName: practice.practicalProjectName,
          practiceTime: practice.practiceStartTime+"---"+practice.practiceEndTime,
          practicalTeacherName: practice.practicalTeacherName,
          practiceAddress: practice.practiceAddress,
        }
      });
    },

    openAddReservation() {
      this.studentSelectType = 'addReservation';
      this.studentTitle = `添加预约学员（${this.currentPractice.practiceAppointmentName || ''}）`;
      this.studentSelectOpen = true;
      this.selectedStudents = [];
      this.resetStudentQuery();
    },

    getTrainingTypeLabel(type) {
      return this.dict.label.training_type?.[type] !== undefined
        ? this.dict.label.training_type[type]
        : `未知类型(${type})`;
    },

    closeReservation() {
      this.reservationOpen = false;
      this.selectedReservations = [];
      this.canSignIn = false;
    },

    getReservationList() {
      this.reservationLoading = true;
      const params = {
        practiceId: this.currentPractice.practiceAppointmentId,
        name: this.reservationQuery.name || '',
        idCard: this.reservationQuery.idCard || '',
        source: this.reservationQuery.source || '',
        signStatus: this.reservationQuery.signStatus || '',
        projectId: this.reservationQuery.projectId || '',
        pageNum: this.reservationQuery.pageNum,
        pageSize: this.reservationQuery.pageSize
      };

      this.$api.training.practiceAppointment.listPracticeReservation(params).then(res => {
        if (res.code === 200) {
          this.reservationList = res.rows;
          this.reservationTotal = res.total;
          this.canSignIn = res.rows.some(item => item.signStatus === '0');
        } else {
          this.$message.error(res.msg || '获取预约列表失败');
          this.reservationList = [];
          this.reservationTotal = 0;
          this.canSignIn = false;
        }
      }).catch(err => {
        console.error('获取预约列表异常：', err);
        this.$message.error('网络异常，请重试');
        this.reservationList = [];
        this.reservationTotal = 0;
        this.canSignIn = false;
      }).finally(() => {
        this.reservationLoading = false;
      });
    },

    resetReservationQuery() {
      if (this.$refs.reservationQueryForm) this.$refs.reservationQueryForm.resetFields();
      this.reservationQuery.projectId = null;
      if (this.$refs.reservationProjectSelectelTree) {
        this.$refs.reservationProjectSelectelTree.setCurrentKey(null);
      }
      this.getReservationList();
    },

    handleReservationSelection(selection) {
      this.selectedReservations = selection;
      this.canSignIn = selection.some(item => item.signStatus === '0');
    },

    handleSignIn(row) {
      if (this.isPracticeExpired) {
        this.$message.warning('实践已结束，无法进行签到');
        return;
      }

      this.$confirm(`确定要为【${row.name}】签到吗？`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消'
      }).then(() => {
        const signData = {
          reservationId: row.reservationId,
          signTime: dateToStr(new Date())
        };

        this.$api.training.practiceAppointment.signInPractice(signData).then(res => {
          if (res.code === 200) {
            this.$message.success('签到成功');
            this.getReservationList();
          } else {
            this.$message.error(res.msg || '签到失败');
          }
        }).catch(err => {
          console.error('签到异常：', err);
          this.$message.error('网络异常，请重试');
        });
      });
    },

    handleBatchSignIn() {
      if (this.isPracticeExpired) {
        this.$message.warning('实践已结束，无法进行批量签到');
        return;
      }

      const unsignedReservations = this.selectedReservations.filter(item => item.signStatus === '0');
      if (unsignedReservations.length === 0) {
        this.$message.warning('请选择未签到的学员');
        return;
      }

      this.$confirm(`确定要为选中的${unsignedReservations.length}名学员签到吗？`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消'
      }).then(() => {
        const signData = {
          reservationIds: unsignedReservations.map(item => item.reservationId),
          signTime: dateToStr(new Date())
        };

        this.$api.training.practiceAppointment.batchSignInPractice(signData).then(res => {
          if (res.code === 200) {
            this.$message.success('批量签到成功');
            this.selectedReservations = [];
            this.canSignIn = false;
            this.getReservationList();
          } else {
            this.$message.error(res.msg || '批量签到失败');
          }
        }).catch(err => {
          console.error('批量签到异常：', err);
          this.$message.error('网络异常，请重试');
        });
      });
    },

    handleCancelReservation(row) {
      this.$confirm(`确定要取消【${row.name}】的预约吗？`, '警告', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$api.training.practiceAppointment.cancelPracticeReservation(row.reservationId).then(res => {
          if (res.code === 200) {
            this.$message.success('取消预约成功');
            this.getReservationList();
          } else {
            this.$message.error(res.msg || '取消预约失败');
          }
        }).catch(err => {
          console.error('取消预约异常：', err);
          this.$message.error('网络异常，请重试');
        });
      });
    },

    handleBatchCancelReservation() {
      if (this.selectedReservations.length === 0) return;

      this.$confirm(`确定要取消选中的${this.selectedReservations.length}名学员的预约吗？`, '警告', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const reservationIds = this.selectedReservations.map(item => item.reservationId);
        this.$api.training.practiceAppointment.batchCancelPracticeReservation(reservationIds).then(res => {
          if (res.code === 200) {
            this.$message.success('批量取消预约成功');
            this.selectedReservations = [];
            this.canSignIn = false;
            this.getReservationList();
          } else {
            this.$message.error(res.msg || '批量取消预约失败');
          }
        }).catch(err => {
          console.error('批量取消预约异常：', err);
          this.$message.error('网络异常，请重试');
        });
      });
    },

    // 其他功能
    handleDelete(row) {
      const ids = row.practiceAppointmentId!==null && row.practiceAppointmentId !==undefined ? [row.practiceAppointmentId] : this.ids;
      if (ids.length === 0) {
        this.$message.warning("请选择需要删除的实践项目");
        return;
      }
      this.$confirm(
        `确定要删除选中的${ids.length}个实践项目吗？删除后数据将无法恢复！`,
        "警告",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      ).then(() => {
        removePracticeAppointment(ids).then(res => {
          if (res.code === 200) {
            this.$message.success("删除成功");
            this.getList();
            this.ids = [];
            this.single = true;
            this.multiple = true;
          } else {
            this.$message.error(res.msg || "删除失败，请重试");
          }
        }).catch(err => {
          console.error("删除实践异常：", err);
          this.$message.error("网络异常，删除操作失败");
        });
      }).catch(() => {
        this.$message.info("已取消删除操作");
      });
    },

    handleExport() {
      const params = {
        projectName: this.queryParams.practiceProject || '',
        practicalType: this.queryParams.practiceStatus || '',
        appointmentType: this.queryParams.reservationStatus || '',
        practiceStartTime: this.queryParams.practiceTime[0] || '',
        practiceEndTime: this.queryParams.practiceTime[1] || ''
      };

      this.$confirm("确定要导出符合条件的实践数据吗？", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      }).then(() => {
        try {
          const url = `/api/training/practice/export?${new URLSearchParams(params)}`;
          const link = document.createElement('a');
          link.href = url;
          link.download = `实践数据_${new Date().getTime()}.xlsx`;
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
          this.$message.success("导出请求已发送，正在生成文件");
        } catch (err) {
          console.error("导出异常：", err);
          this.$message.error("导出失败，请检查网络连接");
        }
      });
    },

    handleNotifyStudents() {
      if (this.ids.length === 0) {
        this.$message.warning("请选择需要通知学员的实践项目");
        return;
      }

      const notifyData = {
        practiceIds: this.ids,
        notifyType: "1",
        notifyContent: `您预约的实践项目即将开始，请准时参加（${new Date().toLocaleDateString()}）`
      };

      this.$confirm(
        `确定要向选中的${this.ids.length}个实践项目的所有预约学员发送通知吗？`,
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "info"
        }
      ).then(() => {
        this.$api.training.practiceAppointment.notifyPracticeStudents(notifyData).then(res => {
          if (res.code === 200) {
            this.$message.success(`已成功向${res.data.notifyCount}名学员发送通知`);
          } else {
            this.$message.error(res.msg || "通知发送失败，请重试");
          }
        }).catch(err => {
          console.error("发送通知异常：", err);
          this.$message.error("网络异常，通知发送失败");
        });
      });
    },

    handleSignInQr() {
      if (this.ids.length !== 1) {
        this.$message.warning("请选择单个实践项目生成签到二维码");
        return;
      }

      const practice = this.practiceList.find(p => p.practiceAppointmentId === this.ids[0]);
      if (!practice) {
        this.$message.error("未找到选中的实践项目信息");
        return;
      }

      if (new Date(practice.practiceEndTime) < new Date()) {
        this.$message.warning("该实践已结束，无法生成签到二维码");
        return;
      }

      this.currentPractice = { ...practice };
      this.qrCodeOpen = true;
      this.qrExpireCountdown = 900;

      if (this.qrTimer) clearInterval(this.qrTimer);
      this.qrTimer = setInterval(() => {
        this.qrExpireCountdown--;
        if (this.qrExpireCountdown <= 0) {
          clearInterval(this.qrTimer);
        }
      }, 1000);
    },

    refreshQrCode() {
      if (!this.currentPractice.practiceAppointmentId) return;

      this.isRefreshingQr = true;
      const qrData = {
        practiceId: this.currentPractice.practiceAppointmentId
      };

      this.$api.training.practiceAppointment.refreshPracticeQrCode(qrData).then(res => {
        if (res.code === 200) {
          this.qrExpireCountdown = 900;
          if (this.qrTimer) clearInterval(this.qrTimer);
          this.qrTimer = setInterval(() => {
            this.qrExpireCountdown--;
            if (this.qrExpireCountdown <= 0) clearInterval(this.qrTimer);
          }, 1000);

          this.$message.success("二维码已刷新，新有效期15分钟");
        } else {
          this.$message.error(res.msg || "二维码刷新失败");
        }
      }).catch(err => {
        console.error("刷新二维码异常：", err);
        this.$message.error("网络异常，二维码刷新失败");
      }).finally(() => {
        this.isRefreshingQr = false;
      });
    },

    handleSignInStatus() {
      if (this.ids.length !== 1) {
        this.$message.warning("请选择单个实践项目");
        return;
      }
      const practice = this.practiceList.find(p => p.practiceAppointmentId === this.ids[0]);
      this.$router.push({
        name: '实践预约签到详情',
        params: {
          practiceAppointmentId:practice.practiceAppointmentId,
          practicalProjectName: practice.practicalProjectName,
          practiceTime: practice.practiceStartTime+"---"+practice.practiceEndTime,
          practicalTeacherName: practice.practicalTeacherName,
          practiceAddress: practice.practiceAddress,
        }
      });
    }
  }
};
</script>

<style scoped>
.app-container {
  height: 100%;
  overflow: hidden;
  padding: 15px;
  background-color: #f5f7fa;
}

.el-advanced-search-container {
  background: #fff;
  border: 1px solid #e6ebf5;
  border-radius: 8px;
  padding: 24px;
  margin-bottom: 16px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

.class-tag-group {
  display: inline-block;
  margin-left: 10px;
  vertical-align: middle;
}

.empty-tip {
  color: #999;
  margin-left: 10px;
  font-size: 12px;
}

.qr-countdown {
  margin-top: 10px;
  font-size: 12px;
  color: #666;
}

.qr-countdown.expired {
  color: #f56c6c;
}

.project-name {
  font-size: 12px;
  margin-top: 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 160px;
  margin-left: auto;
  margin-right: auto;
}

.reservation-info {
  background-color: #f5f7fa;
  padding: 15px;
  border-radius: 6px;
  line-height: 1.8;
}
.el-button { padding: 6px 10px; }

.dialog-footer {
  text-align: right;
  padding: 10px 20px 20px;
}

.el-table {
  background: #fff;
  margin-bottom: 16px;
}

.pagination {
  margin-top: 15px;
  text-align: right;
}

::v-deep .main-select-tree .el-select__tags {
  display: none;
}
::v-deep .main-select-tree .el-select__input {
  display: none;
}
::v-deep .main-select-tree .el-select__placeholder {
  text-align: left;
  color: #909399;
}

::v-deep .main-select-el-tree .el-tree-node.is-current > .el-tree-node__content {
  font-weight: bold;
  color: #409eff;
  background-color: #f5faff;
}

::v-deep .main-select-el-tree .el-tree-node__content:hover {
  background-color: #f5f7fa;
}

::v-deep .main-select-el-tree {
  max-height: 300px;
  overflow-y: auto;
}

/* 指定班级弹窗样式 */
.flex-layout {
  display: flex;
  gap: 20px;
  height: 500px; /* 固定高度，避免滚动冲突 */
}

.tree-area {
  width: 260px;
  display: flex;
  flex-direction: column;
}

::v-deep .tree-area .el-tree {
  flex: 1;
  overflow-y: auto;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
  padding: 5px;
}

.content-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
</style>
